"""
序列化适配器 - 统一的序列化接口
支持多种序列化格式的自动选择和性能监控
"""

import time
import hashlib
from typing import Dict, Any, Optional, Union, List
from dataclasses import dataclass, asdict
from enum import Enum

from .protobuf import ProtobufSerializer, PROTOBUF_AVAILABLE
from .msgpack import MessagePackSerializer, MSGPACK_AVAILABLE
from .json import OptimizedJsonSerializer


class SerializationFormat(Enum):
    """序列化格式枚举"""
    PROTOBUF = "protobuf"
    MSGPACK = "msgpack"
    JSON = "json"
    AUTO = "auto"


@dataclass
class FormatStats:
    """格式统计信息"""
    format_name: str
    total_operations: int = 0
    total_bytes: int = 0
    avg_serialize_time: float = 0.0
    avg_deserialize_time: float = 0.0
    error_count: int = 0
    last_used: float = 0.0


@dataclass
class AdapterStats:
    """适配器统计信息"""
    total_operations: int = 0
    format_stats: Dict[str, FormatStats] = None
    auto_selections: Dict[str, int] = None

    def __post_init__(self):
        if self.format_stats is None:
            self.format_stats = {}
        if self.auto_selections is None:
            self.auto_selections = {}


class FormatDetector:
    """格式检测器"""

    @staticmethod
    def detect_format(data: bytes) -> Optional[SerializationFormat]:
        """自动检测序列化格式"""
        if len(data) < 2:
            return None

        # 检查压缩标记
        payload = data[1:] if data[0] in (0x00, 0x01) else data

        if len(payload) == 0:
            return None

        # Protocol Buffers检测
        # protobuf通常以特定的varint模式开始
        if FormatDetector._is_protobuf(payload):
            return SerializationFormat.PROTOBUF

        # MessagePack检测
        # MessagePack有特定的类型标记
        if FormatDetector._is_msgpack(payload):
            return SerializationFormat.MSGPACK

        # JSON检测
        # JSON通常以 { 或 [ 开始
        if FormatDetector._is_json(payload):
            return SerializationFormat.JSON

        return None

    @staticmethod
    def _is_protobuf(data: bytes) -> bool:
        """检测是否为Protocol Buffers格式"""
        try:
            # 简单的protobuf检测：检查是否包含varint编码
            if len(data) < 2:
                return False

            # protobuf消息通常以字段标记开始
            first_byte = data[0]
            # 检查是否为有效的protobuf字段标记
            wire_type = first_byte & 0x07
            field_number = first_byte >> 3

            return wire_type <= 5 and field_number > 0
        except:
            return False

    @staticmethod
    def _is_msgpack(data: bytes) -> bool:
        """检测是否为MessagePack格式"""
        try:
            if len(data) == 0:
                return False

            first_byte = data[0]

            # MessagePack格式标记
            # fixmap: 1000xxxx
            # fixarray: 1001xxxx
            # fixstr: 101xxxxx
            # nil: 0xc0
            # false: 0xc2, true: 0xc3
            # bin8: 0xc4, bin16: 0xc5, bin32: 0xc6
            # ext8: 0xc7, ext16: 0xc8, ext32: 0xc9
            # float32: 0xca, float64: 0xcb
            # uint8: 0xcc, uint16: 0xcd, uint32: 0xce, uint64: 0xcf
            # int8: 0xd0, int16: 0xd1, int32: 0xd2, int64: 0xd3
            # fixext1: 0xd4, fixext2: 0xd5, fixext4: 0xd6, fixext8: 0xd7, fixext16: 0xd8
            # str8: 0xd9, str16: 0xda, str32: 0xdb
            # array16: 0xdc, array32: 0xdd
            # map16: 0xde, map32: 0xdf

            return (
                    (first_byte & 0xf0) == 0x80 or  # fixmap
                    (first_byte & 0xf0) == 0x90 or  # fixarray
                    (first_byte & 0xe0) == 0xa0 or  # fixstr
                    first_byte in range(0xc0, 0xe0) or  # 其他类型
                    (first_byte & 0x80) == 0x00  # positive fixint
            )
        except:
            return False

    @staticmethod
    def _is_json(data: bytes) -> bool:
        """检测是否为JSON格式"""
        try:
            # 跳过空白字符
            start_idx = 0
            while start_idx < len(data) and data[start_idx:start_idx + 1] in b' \t\n\r':
                start_idx += 1

            if start_idx >= len(data):
                return False

            first_char = chr(data[start_idx])
            # JSON必须以 { [ " 或数字开始
            return first_char in '{"[0123456789-tfn'
        except:
            return False


class SerializationAdapter:
    """序列化适配器 - 统一接口"""

    def __init__(self, default_format: SerializationFormat = SerializationFormat.AUTO,
                 enable_caching: bool = True, cache_size: int = 1000):

        self.default_format = default_format
        self.enable_caching = enable_caching
        self.cache_size = cache_size

        # 初始化序列化器
        self.serializers = {}
        self._init_serializers()

        # 统计信息
        self.stats = AdapterStats()

        # 缓存
        self.cache = {} if enable_caching else None
        self.cache_hits = 0
        self.cache_misses = 0

        # 格式检测器
        self.detector = FormatDetector()

    def _init_serializers(self):
        """初始化所有可用的序列化器"""
        # JSON序列化器（总是可用）
        self.serializers[SerializationFormat.JSON] = OptimizedJsonSerializer()

        # MessagePack序列化器
        if MSGPACK_AVAILABLE:
            self.serializers[SerializationFormat.MSGPACK] = MessagePackSerializer()

        # Protocol Buffers序列化器
        if PROTOBUF_AVAILABLE:
            self.serializers[SerializationFormat.PROTOBUF] = ProtobufSerializer()

    def get_available_formats(self) -> List[SerializationFormat]:
        """获取可用的序列化格式"""
        return list(self.serializers.keys())

    def _select_format(self, obj: Any, hint: Optional[SerializationFormat] = None) -> SerializationFormat:
        """选择最适合的序列化格式"""
        if hint and hint != SerializationFormat.AUTO and hint in self.serializers:
            return hint

        if self.default_format != SerializationFormat.AUTO and self.default_format in self.serializers:
            return self.default_format

        # 自动选择逻辑
        obj_type = type(obj)

        # 对于简单的字典和列表，优先使用MessagePack
        if isinstance(obj, (dict, list)) and SerializationFormat.MSGPACK in self.serializers:
            self.stats.auto_selections['msgpack'] = self.stats.auto_selections.get('msgpack', 0) + 1
            return SerializationFormat.MSGPACK

        # 对于复杂对象，如果有protobuf支持，优先使用
        if hasattr(obj, '__dict__') and SerializationFormat.PROTOBUF in self.serializers:
            self.stats.auto_selections['protobuf'] = self.stats.auto_selections.get('protobuf', 0) + 1
            return SerializationFormat.PROTOBUF

        # 默认使用JSON
        self.stats.auto_selections['json'] = self.stats.auto_selections.get('json', 0) + 1
        return SerializationFormat.JSON

    def _get_cache_key(self, obj: Any) -> str:
        """生成缓存键"""
        if not self.enable_caching:
            return None

        try:
            # 使用对象的字符串表示生成哈希
            obj_str = str(obj)
            return hashlib.md5(obj_str.encode('utf-8')).hexdigest()
        except:
            return None

    def serialize(self, obj: Any, format_hint: Optional[SerializationFormat] = None) -> bytes:
        """序列化对象"""
        start_time = time.perf_counter()

        # 检查缓存
        cache_key = self._get_cache_key(obj)
        if cache_key and cache_key in self.cache:
            self.cache_hits += 1
            return self.cache[cache_key]

        self.cache_misses += 1

        # 选择序列化格式
        selected_format = self._select_format(obj, format_hint)

        try:
            # 获取序列化器
            serializer = self.serializers[selected_format]

            # 执行序列化
            if selected_format == SerializationFormat.PROTOBUF:
                # Protocol Buffers需要特殊处理
                if isinstance(obj, dict) and 'payload' in obj:
                    result = serializer.serialize_data_message(
                        payload=obj['payload'] if isinstance(obj['payload'], bytes) else str(obj['payload']).encode(
                            'utf-8'),
                        **obj.get('header', {})
                    )
                else:
                    # 转换为数据消息格式
                    payload = str(obj).encode('utf-8') if not isinstance(obj, bytes) else obj
                    result = serializer.serialize_data_message(payload=payload)
            elif selected_format == SerializationFormat.MSGPACK:
                result = serializer.pack(obj)
            else:  # JSON
                result = serializer.dumps(obj)

            # 添加格式标记
            format_marker = selected_format.value.encode('utf-8')[:4].ljust(4, b'\x00')
            final_result = format_marker + result

            # 更新缓存
            if cache_key and len(self.cache) < self.cache_size:
                self.cache[cache_key] = final_result

            # 更新统计
            self._update_format_stats(selected_format, 'serialize', time.perf_counter() - start_time, len(final_result))
            self.stats.total_operations += 1

            return final_result

        except Exception as e:
            self._update_format_error(selected_format)
            raise

    def deserialize(self, data: bytes, format_hint: Optional[SerializationFormat] = None) -> Any:
        """反序列化对象"""
        start_time = time.perf_counter()

        if len(data) < 4:
            raise ValueError("数据太短，无法包含格式标记")

        try:
            # 提取格式标记
            format_marker = data[:4]
            payload = data[4:]

            # 确定格式
            if format_hint and format_hint != SerializationFormat.AUTO:
                selected_format = format_hint
            else:
                # 从标记中确定格式
                format_name = format_marker.rstrip(b'\x00').decode('utf-8')
                try:
                    selected_format = SerializationFormat(format_name)
                except ValueError:
                    # 如果标记无效，尝试自动检测
                    detected_format = self.detector.detect_format(payload)
                    selected_format = detected_format or SerializationFormat.JSON

            # 获取序列化器
            if selected_format not in self.serializers:
                raise ValueError(f"不支持的序列化格式: {selected_format}")

            serializer = self.serializers[selected_format]

            # 执行反序列化
            if selected_format == SerializationFormat.PROTOBUF:
                result = serializer.deserialize(payload)
            elif selected_format == SerializationFormat.MSGPACK:
                result = serializer.unpack(payload)
            else:  # JSON
                result = serializer.loads(payload)

            # 更新统计
            self._update_format_stats(selected_format, 'deserialize', time.perf_counter() - start_time, len(data))
            self.stats.total_operations += 1

            return result

        except Exception as e:
            if 'selected_format' in locals():
                self._update_format_error(selected_format)
            raise

    def _update_format_stats(self, format_type: SerializationFormat, operation: str, duration: float, size: int):
        """更新格式统计信息"""
        format_name = format_type.value

        if format_name not in self.stats.format_stats:
            self.stats.format_stats[format_name] = FormatStats(format_name)

        stats = self.stats.format_stats[format_name]
        stats.total_operations += 1
        stats.total_bytes += size
        stats.last_used = time.time()

        # 更新平均时间
        if operation == 'serialize':
            if stats.total_operations == 1:
                stats.avg_serialize_time = duration
            else:
                alpha = 0.1
                stats.avg_serialize_time = alpha * duration + (1 - alpha) * stats.avg_serialize_time
        else:  # deserialize
            if stats.total_operations == 1:
                stats.avg_deserialize_time = duration
            else:
                alpha = 0.1
                stats.avg_deserialize_time = alpha * duration + (1 - alpha) * stats.avg_deserialize_time

    def _update_format_error(self, format_type: SerializationFormat):
        """更新格式错误统计"""
        format_name = format_type.value

        if format_name not in self.stats.format_stats:
            self.stats.format_stats[format_name] = FormatStats(format_name)

        self.stats.format_stats[format_name].error_count += 1

    def get_stats(self) -> Dict[str, Any]:
        """获取适配器统计信息"""
        stats_dict = asdict(self.stats)

        # 添加缓存统计
        if self.enable_caching:
            total_cache_requests = self.cache_hits + self.cache_misses
            stats_dict['cache'] = {
                'enabled': True,
                'size': len(self.cache),
                'max_size': self.cache_size,
                'hits': self.cache_hits,
                'misses': self.cache_misses,
                'hit_rate': self.cache_hits / total_cache_requests if total_cache_requests > 0 else 0.0
            }
        else:
            stats_dict['cache'] = {'enabled': False}

        # 添加序列化器统计
        serializer_stats = {}
        for format_type, serializer in self.serializers.items():
            if hasattr(serializer, 'get_stats'):
                serializer_stats[format_type.value] = serializer.get_stats()

        stats_dict['serializer_stats'] = serializer_stats

        return stats_dict

    def reset_stats(self):
        """重置统计信息"""
        self.stats = AdapterStats()
        self.cache_hits = 0
        self.cache_misses = 0

        # 重置各序列化器的统计
        for serializer in self.serializers.values():
            if hasattr(serializer, 'reset_stats'):
                serializer.reset_stats()

    def clear_cache(self):
        """清空缓存"""
        if self.cache:
            self.cache.clear()

    def benchmark(self, test_data: list, iterations: int = 1000) -> Dict[str, Any]:
        """性能基准测试"""
        import random

        results = {}

        # 测试每种可用格式
        for format_type in self.get_available_formats():
            print(f"测试格式: {format_type.value}")

            # 重置统计
            self.reset_stats()

            # 准备测试数据
            test_objects = []
            for _ in range(iterations):
                data_item = random.choice(test_data)
                test_objects.append(data_item)

            # 序列化基准测试
            start_time = time.perf_counter()
            serialized_messages = []

            for obj in test_objects:
                try:
                    serialized = self.serialize(obj, format_hint=format_type)
                    serialized_messages.append(serialized)
                except Exception as e:
                    print(f"序列化错误 ({format_type.value}): {e}")
                    continue

            serialize_time = time.perf_counter() - start_time

            # 反序列化基准测试
            start_time = time.perf_counter()

            for serialized in serialized_messages:
                try:
                    self.deserialize(serialized, format_hint=format_type)
                except Exception as e:
                    print(f"反序列化错误 ({format_type.value}): {e}")
                    continue

            deserialize_time = time.perf_counter() - start_time

            # 计算结果
            total_size = sum(len(msg) for msg in serialized_messages)
            successful_operations = len(serialized_messages)

            if successful_operations > 0:
                results[format_type.value] = {
                    'iterations': successful_operations,
                    'serialize_time': serialize_time,
                    'deserialize_time': deserialize_time,
                    'serialize_rate': successful_operations / serialize_time if serialize_time > 0 else 0,
                    'deserialize_rate': successful_operations / deserialize_time if deserialize_time > 0 else 0,
                    'total_size': total_size,
                    'avg_message_size': total_size / successful_operations,
                    'throughput_mbps': (total_size / (1024 * 1024)) / (serialize_time + deserialize_time) if (
                                                                                                                         serialize_time + deserialize_time) > 0 else 0,
                    'stats': self.get_stats()
                }

        return results


# 使用示例
if __name__ == "__main__":
    # 创建适配器
    adapter = SerializationAdapter()

    print(f"可用格式: {[f.value for f in adapter.get_available_formats()]}")

    # 测试数据
    test_data = {
        'string': 'Hello, Adapter!',
        'number': 42,
        'float': 3.14159,
        'boolean': True,
        'null': None,
        'list': [1, 2, 3, 4, 5],
        'dict': {'nested': 'value'},
    }

    # 自动格式选择
    serialized = adapter.serialize(test_data)
    print(f"自动序列化: {len(serialized)} bytes")

    deserialized = adapter.deserialize(serialized)
    print(f"自动反序列化: {deserialized}")

    # 指定格式
    for format_type in adapter.get_available_formats():
        try:
            serialized = adapter.serialize(test_data, format_hint=format_type)
            deserialized = adapter.deserialize(serialized, format_hint=format_type)
            print(f"{format_type.value}: {len(serialized)} bytes")
        except Exception as e:
            print(f"{format_type.value}: 错误 - {e}")

    # 获取统计信息
    stats = adapter.get_stats()
    print(f"\n统计信息: {stats}")

    # 性能基准测试
    print("\n开始性能基准测试...")
    benchmark_data = [
        {'id': i, 'data': f'message_{i}', 'value': i * 3.14}
        for i in range(10)
    ]

    benchmark_results = adapter.benchmark(benchmark_data, iterations=100)

    print("\n基准测试结果:")
    for format_name, result in benchmark_results.items():
        print(f"{format_name}:")
        print(f"  序列化速率: {result['serialize_rate']:.0f} ops/s")
        print(f"  反序列化速率: {result['deserialize_rate']:.0f} ops/s")
        print(f"  平均消息大小: {result['avg_message_size']:.1f} bytes")
        print(f"  吞吐量: {result['throughput_mbps']:.2f} MB/s")